/*********************\
* Author:Dzlua
* QQ:505544956
* Time:2017/03/15
\**********************/
#include "StdAfx.h"

namespace DuiLib {

SDWindow::SDWindow(LPCTSTR name)
        : m_bAutoDelete(false)
{
    m_pm = new CPaintManagerUI;
    SDIScript* script = SDPtr->GetStript();
    if (script) script->AddWnd(this, _T("Window"));

    m_name.Empty();
    if (name) {
        m_name = name;
    }
}

SDWindow::~SDWindow()
{
    if (m_pm) {
        delete m_pm;
        m_pm = NULL;
    }
}

void SDWindow::SetAutoDelete(bool bAutoDelete)
{
    m_bAutoDelete = bAutoDelete;
}

bool SDWindow::IsAutoDelete()
{
    return m_bAutoDelete;
}

// called by CControlUI::~CControlUI
void SDWindow::OnRemoveControl(CControlUI* ctrl)
{
    SDIScript* script = SDPtr->GetStript();
    if (script) script->RemoveCtrl(this, ctrl);
}

// called by CDialogBuilder::_Parse
void SDWindow::OnAfterCreateControl(CControlUI* ctrl, LPCTSTR ctrlname)
{
    SDIScript* script = SDPtr->GetStript();
    if (script) script->AddCtrl(this, ctrl, ctrlname);
}

//---------------------------------------//
//file or str
BOOL SDWindow::BuildWindow(LPCTSTR xmlOrStr)
{
    CControlUI* pRoot = BuildControl(xmlOrStr);
    if (!pRoot) return FALSE;
    m_pm->AttachDialog(pRoot);
    return TRUE;
}

//file or str
CControlUI* SDWindow::BuildControl(LPCTSTR xmlOrStr)
{
    CControlUI* pRoot = NULL;
    CDialogBuilder builder;
    CDuiString sSkinType = _T("");
    if (!sSkinType.IsEmpty()) {
        STRINGorID xml(_ttoi(xmlOrStr));
        pRoot = builder.Create(xml, sSkinType, this, m_pm);
    } else {
        pRoot = builder.Create(xmlOrStr, (UINT)0, this, m_pm);
    }
    return pRoot;
}

void SDWindow::Minimize()
{
    PostMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); 
}

void SDWindow::Maximize()
{
    PostMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}

void SDWindow::Restore()
{
    PostMessage(WM_SYSCOMMAND, SC_RESTORE, 0);
}

void* SDWindow::DoScript(SPDUI_MSG msg, void* data1, void* data2)
{
    SDIScript* script = SDPtr->GetStript();
    if (!script) return 0;
    return script->HandleMessage(this, msg, data1, data2);
}

void* SDWindow::DoScript(SPDUI_MSG msg, WPARAM wParam, LPARAM lParam)
{
    return DoScript(msg, (void*)wParam, (void*)lParam);
}

//---------------------------------------//

LONG SDWindow::GetStyle()
{
    LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
    styleValue &= ~WS_CAPTION;
    return styleValue;
}

//CWindowWnd::
UINT SDWindow::GetClassStyle() const
{
	return CS_DBLCLKS;
}

BOOL SDWindow::IsStaticControl(CControlUI *pControl)
{
    BOOL bRet = FALSE;
    if (!pControl)
    {
        return bRet;
    }

    CDuiString strClassName;
    std::vector<CDuiString> vctStaticName;

    strClassName = pControl->GetClass();
    strClassName.MakeLower();
    vctStaticName.push_back(_T("controlui"));
    vctStaticName.push_back(_T("textui"));
    vctStaticName.push_back(_T("labelui"));
    vctStaticName.push_back(_T("containerui"));
    vctStaticName.push_back(_T("horizontallayoutui"));
    vctStaticName.push_back(_T("verticallayoutui"));
    vctStaticName.push_back(_T("tablayoutui"));
    vctStaticName.push_back(_T("childlayoutui"));
    vctStaticName.push_back(_T("dialoglayoutui"));
    vctStaticName.push_back(_T("progresscontainerui"));
    std::vector<CDuiString>::iterator it = std::find(vctStaticName.begin(), vctStaticName.end(), strClassName);
    if (vctStaticName.end() != it)
    {
        CControlUI* pParent = pControl->GetParent();
        while (pParent)
        {
            strClassName = pParent->GetClass();
            strClassName.MakeLower();
            it = std::find(vctStaticName.begin(), vctStaticName.end(), strClassName);
            if (vctStaticName.end() == it)
            {
                return bRet;
            }

            pParent = pParent->GetParent();
        }

        bRet = TRUE;
    }

    return bRet;
}

//---------------------------------------//
//CWindowWnd::
LPCTSTR SDWindow::GetWindowClassName() const
{
    return _T("SPDUI_CLASSNAME");
}

//CWindowWnd::
LRESULT SDWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = 0;
    BOOL bHandled = TRUE;
    switch (uMsg)
    {
    case WM_CREATE:			lRes = OnCreate(wParam, lParam, bHandled); break;
    case WM_CLOSE:			lRes = OnClose(wParam, lParam, bHandled); break;
    case WM_DESTROY:		lRes = OnDestroy(wParam, lParam, bHandled); break;
#if defined(WIN32) && !defined(UNDER_CE)
    case WM_NCACTIVATE:		lRes = OnNcActivate(wParam, lParam, bHandled); break;
    case WM_NCCALCSIZE:		lRes = OnNcCalcSize(wParam, lParam, bHandled); break;
    case WM_NCPAINT:		lRes = OnNcPaint(wParam, lParam, bHandled); break;
    case WM_NCHITTEST:		lRes = OnNcHitTest(wParam, lParam, bHandled); break;
    case WM_GETMINMAXINFO:	lRes = OnGetMinMaxInfo(wParam, lParam, bHandled); break;
    case WM_MOUSEWHEEL:		lRes = OnMouseWheel(wParam, lParam, bHandled); break;
#endif
    case WM_SIZE:			lRes = OnSize(wParam, lParam, bHandled); break;
    case WM_CHAR:		    lRes = OnChar(wParam, lParam, bHandled); break;
    case WM_SYSCOMMAND:		lRes = OnSysCommand(wParam, lParam, bHandled); break;
    case WM_KEYDOWN:		lRes = OnKeyDown(wParam, lParam, bHandled); break;
    case WM_KEYUP:		    lRes = OnKeyUp(wParam, lParam, bHandled); break;
    case WM_KILLFOCUS:		lRes = OnKillFocus(wParam, lParam, bHandled); break;
    case WM_SETFOCUS:		lRes = OnSetFocus(wParam, lParam, bHandled); break;
    case WM_LBUTTONUP:		lRes = OnLButtonUp(wParam, lParam, bHandled); break;
    case WM_LBUTTONDOWN:	lRes = OnLButtonDown(wParam, lParam, bHandled); break;
    case WM_MOUSEMOVE:		lRes = OnMouseMove(wParam, lParam, bHandled); break;
    case WM_MOUSEHOVER:	    lRes = OnMouseHover(wParam, lParam, bHandled); break;
    default:				bHandled = FALSE; break;
    }
    if (bHandled) return lRes;

    lRes = OnHandleMessage(uMsg, wParam, lParam, bHandled);
    if (bHandled) return lRes;

    if (m_pm->MessageHandler(uMsg, wParam, lParam, lRes))
        return lRes;
    return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
}

//CWindowWnd::
void SDWindow::OnFinalMessage(HWND hWnd)
{
    m_pm->RemovePreMessageFilter(this);
    m_pm->RemoveNotifier(this);
    m_pm->ReapObjects(m_pm->GetRoot());

    SDIScript* script = SDPtr->GetStript();
    if (script) script->RemoveWnd(this);

    SDPtr->RemoveWindow(this);
}

//INotifyUI::
void SDWindow::Notify(TNotifyUI& msg)
{
    OnNotify(msg);
}

//IMessageFilterUI::
LRESULT SDWindow::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
    return FALSE;
}

//IDialogBuilderCallback::
CControlUI* SDWindow::CreateControl(LPCTSTR pstrClass)
{
    return OnCreateControl(pstrClass);
}

//IQueryControlText::
LPCTSTR SDWindow::QueryControlText(LPCTSTR lpstrId, LPCTSTR lpstrType)
{
    return NULL;
}

//---------------------------------------//
LRESULT SDWindow::OnCreate(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
    styleValue &= ~WS_CAPTION;
    ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);

    RECT rcClient;
    ::GetClientRect(*this, &rcClient);
    ::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_FRAMECHANGED);

    if (m_name.IsEmpty()) m_pm->Init(m_hWnd, NULL);
    else m_pm->Init(m_hWnd, m_name.GetData());
    m_pm->AddPreMessageFilter(this);
    m_pm->AddNotifier(this);

    OnCreate();

    return 0;
}

LRESULT SDWindow::OnClose(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_CLOSE, wParam, lParam);
    return 0;
}

LRESULT SDWindow::OnDestroy(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_DESTROY, wParam, lParam);
    return 0;
}

#if defined(WIN32) && !defined(UNDER_CE)
LRESULT SDWindow::OnNcActivate(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if( ::IsIconic(*this) ) bHandled = FALSE;
    return (wParam == 0) ? TRUE : FALSE;
}

LRESULT SDWindow::OnNcCalcSize(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    return 0;
}

LRESULT SDWindow::OnNcPaint(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    return 0;
}

LRESULT SDWindow::OnNcHitTest(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
    ::ScreenToClient(*this, &pt);

    RECT rcClient;
    ::GetClientRect(*this, &rcClient);

    if (!::IsZoomed(*this))
    {
        RECT rcSizeBox = m_pm->GetSizeBox();
        if (pt.y < rcClient.top + rcSizeBox.top)
        {
            if (pt.x < rcClient.left + rcSizeBox.left) return HTTOPLEFT;
            if (pt.x > rcClient.right - rcSizeBox.right) return HTTOPRIGHT;
            return HTTOP;
        }
        else if (pt.y > rcClient.bottom - rcSizeBox.bottom)
        {
            if (pt.x < rcClient.left + rcSizeBox.left) return HTBOTTOMLEFT;
            if (pt.x > rcClient.right - rcSizeBox.right) return HTBOTTOMRIGHT;
            return HTBOTTOM;
        }

        if (pt.x < rcClient.left + rcSizeBox.left) return HTLEFT;
        if (pt.x > rcClient.right - rcSizeBox.right) return HTRIGHT;
    }

    RECT rcCaption = m_pm->GetCaptionRect();
    if (-1 == rcCaption.bottom)
    {
        rcCaption.bottom = rcClient.bottom;
    }

    if (pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right
        && pt.y >= rcCaption.top && pt.y < rcCaption.bottom)
    {
        CControlUI* pControl = m_pm->FindControl(pt);
        if (IsStaticControl(pControl))
        {
            return HTCAPTION;
        }
    }

    return HTCLIENT;
}

LRESULT SDWindow::OnGetMinMaxInfo(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    MONITORINFO Monitor = {};
    Monitor.cbSize = sizeof(Monitor);
    ::GetMonitorInfo(::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY), &Monitor);
    RECT rcWork = Monitor.rcWork;
    if( Monitor.dwFlags != MONITORINFOF_PRIMARY ) {
        ::OffsetRect(&rcWork, -rcWork.left, -rcWork.top);
    }

    LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
    lpMMI->ptMaxPosition.x	= rcWork.left;
    lpMMI->ptMaxPosition.y	= rcWork.top;
    lpMMI->ptMaxSize.x = rcWork.right - rcWork.left;
    lpMMI->ptMaxSize.y = rcWork.bottom - rcWork.top;
    lpMMI->ptMaxTrackSize.x = rcWork.right - rcWork.left;
    lpMMI->ptMaxTrackSize.y = rcWork.bottom - rcWork.top;
    lpMMI->ptMinTrackSize.x = m_pm->GetMinInfo().cx;
    lpMMI->ptMinTrackSize.y = m_pm->GetMinInfo().cy;

    bHandled = TRUE;
    return 0;
}

LRESULT SDWindow::OnMouseWheel(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT SDWindow::OnMouseHover(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}
#endif

LRESULT SDWindow::OnSize(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    SIZE szRoundCorner = m_pm->GetRoundCorner();
#if defined(WIN32) && !defined(UNDER_CE)
    if( !::IsIconic(*this) ) {
        CDuiRect rcWnd;
        ::GetWindowRect(*this, &rcWnd);
        rcWnd.Offset(-rcWnd.left, -rcWnd.top);
        rcWnd.right++; rcWnd.bottom++;
        HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
        ::SetWindowRgn(*this, hRgn, TRUE);
        ::DeleteObject(hRgn);
    }
#endif
    bHandled = FALSE;
    return 0;
}

LRESULT SDWindow::OnChar(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT SDWindow::OnSysCommand(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if (wParam == SC_CLOSE)
    {
        bHandled = TRUE;
        SendMessage(WM_CLOSE);
        return 0;
    }
#if defined(WIN32) && !defined(UNDER_CE)
    BOOL bZoomed = ::IsZoomed(*this);
    LRESULT lRes = CWindowWnd::HandleMessage(WM_SYSCOMMAND, wParam, lParam);
    if( ::IsZoomed(*this) != bZoomed ) {
        OnZoomed(!bZoomed);
    }
#else
    LRESULT lRes = CWindowWnd::HandleMessage(WM_SYSCOMMAND, wParam, lParam);
#endif
    return lRes;
}

LRESULT SDWindow::OnKeyDown(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_KEYDOWN, wParam, lParam);
    return 0;
}

LRESULT SDWindow::OnKeyUp(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_KEUP, wParam, lParam);
    return 0;
}

LRESULT SDWindow::OnLButtonDown(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT SDWindow::OnLButtonUp(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

LRESULT SDWindow::OnKillFocus(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_KILLFOCUS, wParam, lParam);
    return 0;
}

LRESULT SDWindow::OnSetFocus(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = (BOOL)DoScript(SPDUI_MSG_ON_SETFOCUS, wParam, lParam);
    return 0;
}

LRESULT SDWindow::OnMouseMove(WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}
//---------------------------------------//
void SDWindow::OnCreate()
{
    DoScript(SPDUI_MSG_ON_CREATE);
}

void SDWindow::OnZoomed(bool bZoomed)
{
    DoScript(SPDUI_MSG_ON_ZOOMED, (void*)(bZoomed ? 1 : 0));
}

void SDWindow::OnNotify(TNotifyUI& msg)
{
    DoScript(SPDUI_MSG_ON_NOTIFY, &msg);
}

CControlUI* SDWindow::OnCreateControl(LPCTSTR pstrClass)
{
    return (CControlUI*)DoScript(SPDUI_MSG_ON_CREATECONTROL, (void*)pstrClass);
}

LRESULT SDWindow::OnHandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

}
